{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1f5bafcb-0750-4d39-9be5-3736baae9eb0",
   "metadata": {},
   "source": [
    "# Combining `waterfallPlot()` with Other Geometry Layers\n",
    "\n",
    "This notebook demonstrates how to enrich a waterfall plot with background and foreground layers. Foreground layers can be added using the regular `+` operator. To add background layers, use the new `backgroundLayers` property.\n",
    "\n",
    "Limitations:\n",
    "- Layers must provide their own data\n",
    "- Data coordinates are expected to be numeric"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "80a0cec9-510a-48c3-8412-1f5b867b74fd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "            <div id=\"kotlin_out_0\"></div>\n",
       "            <script type=\"text/javascript\">\n",
       "                            if(!window.kotlinQueues) {\n",
       "                window.kotlinQueues = {};\n",
       "            }\n",
       "            if(!window.kotlinQueues[\"DataFrame\"]) {\n",
       "                var resQueue = [];\n",
       "                window.kotlinQueues[\"DataFrame\"] = resQueue;\n",
       "                window[\"call_DataFrame\"] = function(f) {\n",
       "                    resQueue.push(f);\n",
       "                }\n",
       "            }\n",
       "            (function (){\n",
       "                var modifiers = [(function(script) {\n",
       "    script.src = \"https://cdn.jsdelivr.net/gh/Kotlin/dataframe@3db46ccccaa1291c0627307d64133317f545e6ae/core/src/main/resources/init.js\"\n",
       "    script.type = \"text/javascript\";\n",
       "})];\n",
       "                var e = document.getElementById(\"kotlin_out_0\");\n",
       "                modifiers.forEach(function (gen) {\n",
       "                    var script = document.createElement(\"script\");\n",
       "                    gen(script)\n",
       "                    script.addEventListener(\"load\", function() {\n",
       "                        window[\"call_DataFrame\"] = function(f) {f();};\n",
       "                        window.kotlinQueues[\"DataFrame\"].forEach(function(f) {f();});\n",
       "                        window.kotlinQueues[\"DataFrame\"] = [];\n",
       "                    }, false);\n",
       "                    script.addEventListener(\"error\", function() {\n",
       "                        window[\"call_DataFrame\"] = function(f) {};\n",
       "                        window.kotlinQueues[\"DataFrame\"] = [];\n",
       "                        var div = document.createElement(\"div\");\n",
       "                        div.style.color = 'darkred';\n",
       "                        div.textContent = 'Error loading resource DataFrame';\n",
       "                        document.getElementById(\"kotlin_out_0\").appendChild(div);\n",
       "                    }, false);\n",
       "                    \n",
       "                    e.appendChild(script);\n",
       "                });\n",
       "            })();\n",
       "            </script>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "                <style>\n",
       "                :root {\n",
       "    --background: #fff;\n",
       "    --background-odd: #f5f5f5;\n",
       "    --background-hover: #d9edfd;\n",
       "    --header-text-color: #474747;\n",
       "    --text-color: #848484;\n",
       "    --text-color-dark: #000;\n",
       "    --text-color-medium: #737373;\n",
       "    --text-color-pale: #b3b3b3;\n",
       "    --inner-border-color: #aaa;\n",
       "    --bold-border-color: #000;\n",
       "    --link-color: #296eaa;\n",
       "    --link-color-pale: #296eaa;\n",
       "    --link-hover: #1a466c;\n",
       "}\n",
       "\n",
       ":root[theme=\"dark\"], :root [data-jp-theme-light=\"false\"], .dataframe_dark{\n",
       "    --background: #303030;\n",
       "    --background-odd: #3c3c3c;\n",
       "    --background-hover: #464646;\n",
       "    --header-text-color: #dddddd;\n",
       "    --text-color: #b3b3b3;\n",
       "    --text-color-dark: #dddddd;\n",
       "    --text-color-medium: #b2b2b2;\n",
       "    --text-color-pale: #737373;\n",
       "    --inner-border-color: #707070;\n",
       "    --bold-border-color: #777777;\n",
       "    --link-color: #008dc0;\n",
       "    --link-color-pale: #97e1fb;\n",
       "    --link-hover: #00688e;\n",
       "}\n",
       "\n",
       "p.dataframe_description {\n",
       "    color: var(--text-color-dark);\n",
       "}\n",
       "\n",
       "table.dataframe {\n",
       "    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n",
       "    font-size: 12px;\n",
       "    background-color: var(--background);\n",
       "    color: var(--text-color-dark);\n",
       "    border: none;\n",
       "    border-collapse: collapse;\n",
       "}\n",
       "\n",
       "table.dataframe th, td {\n",
       "    padding: 6px;\n",
       "    border: 1px solid transparent;\n",
       "    text-align: left;\n",
       "}\n",
       "\n",
       "table.dataframe th {\n",
       "    background-color: var(--background);\n",
       "    color: var(--header-text-color);\n",
       "}\n",
       "\n",
       "table.dataframe td {\n",
       "    vertical-align: top;\n",
       "    white-space: nowrap;\n",
       "}\n",
       "\n",
       "table.dataframe th.bottomBorder {\n",
       "    border-bottom-color: var(--bold-border-color);\n",
       "}\n",
       "\n",
       "table.dataframe tbody > tr:nth-child(odd) {\n",
       "    background: var(--background-odd);\n",
       "}\n",
       "\n",
       "table.dataframe tbody > tr:nth-child(even) {\n",
       "    background: var(--background);\n",
       "}\n",
       "\n",
       "table.dataframe tbody > tr:hover {\n",
       "    background: var(--background-hover);\n",
       "}\n",
       "\n",
       "table.dataframe a {\n",
       "    cursor: pointer;\n",
       "    color: var(--link-color);\n",
       "    text-decoration: none;\n",
       "}\n",
       "\n",
       "table.dataframe tr:hover > td a {\n",
       "    color: var(--link-color-pale);\n",
       "}\n",
       "\n",
       "table.dataframe a:hover {\n",
       "    color: var(--link-hover);\n",
       "    text-decoration: underline;\n",
       "}\n",
       "\n",
       "table.dataframe img {\n",
       "    max-width: fit-content;\n",
       "}\n",
       "\n",
       "table.dataframe th.complex {\n",
       "    background-color: var(--background);\n",
       "    border: 1px solid var(--background);\n",
       "}\n",
       "\n",
       "table.dataframe .leftBorder {\n",
       "    border-left-color: var(--inner-border-color);\n",
       "}\n",
       "\n",
       "table.dataframe .rightBorder {\n",
       "    border-right-color: var(--inner-border-color);\n",
       "}\n",
       "\n",
       "table.dataframe .rightAlign {\n",
       "    text-align: right;\n",
       "}\n",
       "\n",
       "table.dataframe .expanderSvg {\n",
       "    width: 8px;\n",
       "    height: 8px;\n",
       "    margin-right: 3px;\n",
       "}\n",
       "\n",
       "table.dataframe .expander {\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "}\n",
       "\n",
       "/* formatting */\n",
       "\n",
       "table.dataframe .null {\n",
       "    color: var(--text-color-pale);\n",
       "}\n",
       "\n",
       "table.dataframe .structural {\n",
       "    color: var(--text-color-medium);\n",
       "    font-weight: bold;\n",
       "}\n",
       "\n",
       "table.dataframe .dataFrameCaption {\n",
       "    font-weight: bold;\n",
       "}\n",
       "\n",
       "table.dataframe .numbers {\n",
       "    color: var(--text-color-dark);\n",
       "}\n",
       "\n",
       "table.dataframe td:hover .formatted .structural, .null {\n",
       "    color: var(--text-color-dark);\n",
       "}\n",
       "\n",
       "table.dataframe tr:hover .formatted .structural, .null {\n",
       "    color: var(--text-color-dark);\n",
       "}\n",
       "\n",
       "\n",
       "                </style>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "   <div id=\"xEuUeg\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"library\">\n",
       "       if(!window.letsPlotCallQueue) {\n",
       "           window.letsPlotCallQueue = [];\n",
       "       }; \n",
       "       window.letsPlotCall = function(f) {\n",
       "           window.letsPlotCallQueue.push(f);\n",
       "       };\n",
       "       (function() {\n",
       "           var script = document.createElement(\"script\");\n",
       "           script.type = \"text/javascript\";\n",
       "           script.src = \"https://cdn.jsdelivr.net/gh/JetBrains/lets-plot@v4.7.0/js-package/distr/lets-plot.min.js\";\n",
       "           script.onload = function() {\n",
       "               window.letsPlotCall = function(f) {f();};\n",
       "               window.letsPlotCallQueue.forEach(function(f) {f();});\n",
       "               window.letsPlotCallQueue = [];\n",
       "               \n",
       "               \n",
       "           };\n",
       "           script.onerror = function(event) {\n",
       "               window.letsPlotCall = function(f) {};\n",
       "               window.letsPlotCallQueue = [];\n",
       "               var div = document.createElement(\"div\");\n",
       "               div.style.color = 'darkred';\n",
       "               div.textContent = 'Error loading Lets-Plot JS';\n",
       "               document.getElementById(\"xEuUeg\").appendChild(div);\n",
       "           };\n",
       "           var e = document.getElementById(\"xEuUeg\");\n",
       "           e.appendChild(script);\n",
       "       })();\n",
       "   </script>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "            <div id=\"kotlin_out_1\"></div>\n",
       "            <script type=\"text/javascript\">\n",
       "                            if(!window.kotlinQueues) {\n",
       "                window.kotlinQueues = {};\n",
       "            }\n",
       "            if(!window.kotlinQueues[\"letsPlotJs\"]) {\n",
       "                var resQueue = [];\n",
       "                window.kotlinQueues[\"letsPlotJs\"] = resQueue;\n",
       "                window[\"call_letsPlotJs\"] = function(f) {\n",
       "                    resQueue.push(f);\n",
       "                }\n",
       "            }\n",
       "            (function (){\n",
       "                var modifiers = [(function(script) {\n",
       "    script.src = \"https://cdn.jsdelivr.net/gh/JetBrains/lets-plot@v4.7.0/js-package/distr/lets-plot.min.js\"\n",
       "    script.type = \"text/javascript\";\n",
       "})];\n",
       "                var e = document.getElementById(\"kotlin_out_1\");\n",
       "                modifiers.forEach(function (gen) {\n",
       "                    var script = document.createElement(\"script\");\n",
       "                    gen(script)\n",
       "                    script.addEventListener(\"load\", function() {\n",
       "                        window[\"call_letsPlotJs\"] = function(f) {f();};\n",
       "                        window.kotlinQueues[\"letsPlotJs\"].forEach(function(f) {f();});\n",
       "                        window.kotlinQueues[\"letsPlotJs\"] = [];\n",
       "                    }, false);\n",
       "                    script.addEventListener(\"error\", function() {\n",
       "                        window[\"call_letsPlotJs\"] = function(f) {};\n",
       "                        window.kotlinQueues[\"letsPlotJs\"] = [];\n",
       "                        var div = document.createElement(\"div\");\n",
       "                        div.style.color = 'darkred';\n",
       "                        div.textContent = 'Error loading resource letsPlotJs';\n",
       "                        document.getElementById(\"kotlin_out_1\").appendChild(div);\n",
       "                    }, false);\n",
       "                    \n",
       "                    e.appendChild(script);\n",
       "                });\n",
       "            })();\n",
       "            </script>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%useLatestDescriptors\n",
    "%use dataframe\n",
    "%use lets-plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "39eabe85-6deb-4cef-b4cd-6ecb37e0b822",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Lets-Plot Kotlin API v.4.11.0. Frontend: Notebook with dynamically loaded JS. Lets-Plot JS v.4.7.0."
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "LetsPlot.getInfo()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "347c9a4e-bcdd-446c-b275-a9bf5a030f50",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "   <div id=\"wvnDYC\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n",
       "   \n",
       "   (function() {\n",
       "   // ----------\n",
       "   \n",
       "   const forceImmediateRender = false;\n",
       "   const responsive = false;\n",
       "   \n",
       "   let sizing = {\n",
       "       width_mode: \"MIN\",\n",
       "       height_mode: \"SCALED\",\n",
       "       width: null, \n",
       "       height: null \n",
       "   };\n",
       "   \n",
       "   const preferredWidth = document.body.dataset.letsPlotPreferredWidth;\n",
       "   if (preferredWidth !== undefined) {\n",
       "       sizing = {\n",
       "           width_mode: 'FIXED',\n",
       "           height_mode: 'SCALED',\n",
       "           width: parseFloat(preferredWidth)\n",
       "       };\n",
       "   }\n",
       "   \n",
       "   const containerDiv = document.getElementById(\"wvnDYC\");\n",
       "   let fig = null;\n",
       "   \n",
       "   function renderPlot() {\n",
       "       if (fig === null) {\n",
       "           const plotSpec = {\n",
       "\"ggtitle\":{\n",
       "\"text\":\"Waterfall with additional layers\"\n",
       "},\n",
       "\"mapping\":{\n",
       "},\n",
       "\"data\":{\n",
       "},\n",
       "\"ggsize\":{\n",
       "\"width\":750.0,\n",
       "\"height\":450.0\n",
       "},\n",
       "\"kind\":\"plot\",\n",
       "\"scales\":[{\n",
       "\"aesthetic\":\"x\",\n",
       "\"name\":\"Accounts\",\n",
       "\"breaks\":[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0],\n",
       "\"labels\":[\"initial\",\"revenue\",\"costs\",\"revenue\",\"costs\",\"revenue\",\"costs\",\"revenue\",\"costs\",\"total\"]\n",
       "},{\n",
       "\"aesthetic\":\"y\",\n",
       "\"name\":\"Values\"\n",
       "},{\n",
       "\"aesthetic\":\"color\",\n",
       "\"name\":\"Flow type\",\n",
       "\"breaks\":[\"Increase\",\"Decrease\",\"Absolute\",\"Total\"],\n",
       "\"values\":[\"#4daf4a\",\"#e41a1c\",\"#377eb8\",\"#377eb8\"]\n",
       "},{\n",
       "\"aesthetic\":\"fill\",\n",
       "\"name\":\"Flow type\",\n",
       "\"breaks\":[\"Increase\",\"Decrease\",\"Absolute\",\"Total\"],\n",
       "\"values\":[\"#4daf4a\",\"#e41a1c\",\"#377eb8\",\"#377eb8\"]\n",
       "},{\n",
       "\"aesthetic\":\"paint_a\",\n",
       "\"scale_mapper_kind\":\"color_hue\",\n",
       "\"guide\":\"none\"\n",
       "}],\n",
       "\"layers\":[{\n",
       "\"mapping\":{\n",
       "\"xmin\":\"period_start\",\n",
       "\"xmax\":\"period_end\",\n",
       "\"paint_a\":\"ai_introduced\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"data\":{\n",
       "\"period_end\":[4.5,8.5],\n",
       "\"ai_introduced\":[false,true],\n",
       "\"period_start\":[0.5,4.5]\n",
       "},\n",
       "\"alpha\":0.2,\n",
       "\"color_by\":\"paint_a\",\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"band\",\n",
       "\"data_meta\":{\n",
       "\"series_annotations\":[{\n",
       "\"type\":\"float\",\n",
       "\"column\":\"period_start\"\n",
       "},{\n",
       "\"type\":\"float\",\n",
       "\"column\":\"period_end\"\n",
       "},{\n",
       "\"type\":\"bool\",\n",
       "\"column\":\"ai_introduced\"\n",
       "}]\n",
       "},\n",
       "\"fill_by\":\"paint_a\"\n",
       "},{\n",
       "\"geom\":\"spoke\",\n",
       "\"data\":{\n",
       "\"..radius..\":[0.09999999999999998,0.09999999999999998,0.09999999999999998,0.09999999999999998,0.09999999999999998,0.09999999999999998,0.09999999999999998,0.09999999999999998,0.09999999999999998,0.0],\n",
       "\"..value..\":[200.0,400.0,250.0,500.0,330.0,480.0,430.0,710.0,685.0,685.0],\n",
       "\"..x..\":[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]\n",
       "},\n",
       "\"mapping\":{\n",
       "\"x\":\"..x..\",\n",
       "\"y\":\"..value..\",\n",
       "\"radius\":\"..radius..\"\n",
       "},\n",
       "\"angle\":0.0,\n",
       "\"position\":{\n",
       "\"name\":\"nudge\",\n",
       "\"x\":0.45\n",
       "}\n",
       "},{\n",
       "\"geom\":\"crossbar\",\n",
       "\"data\":{\n",
       "\"..flow_type..\":[\"Absolute\",\"Increase\",\"Decrease\",\"Increase\",\"Decrease\",\"Increase\",\"Decrease\",\"Increase\",\"Decrease\",\"Total\"],\n",
       "\"..dy..\":[200.0,200.0,-150.0,250.0,-170.0,150.0,-50.0,280.0,-25.0,685.0],\n",
       "\"..x..\":[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0],\n",
       "\"..ymax..\":[null,400.0,400.0,500.0,500.0,480.0,480.0,710.0,710.0,null],\n",
       "\"..label..\":[200.0,200.0,-150.0,250.0,-170.0,150.0,-50.0,280.0,-25.0,685.0],\n",
       "\"..ymin..\":[null,200.0,250.0,250.0,330.0,330.0,430.0,430.0,685.0,null]\n",
       "},\n",
       "\"mapping\":{\n",
       "\"x\":\"..x..\",\n",
       "\"ymin\":\"..ymin..\",\n",
       "\"ymax\":\"..ymax..\",\n",
       "\"fill\":\"..flow_type..\"\n",
       "},\n",
       "\"color\":\"black\",\n",
       "\"size\":0.0,\n",
       "\"linetype\":1,\n",
       "\"width\":0.9,\n",
       "\"show_legend\":false,\n",
       "\"tooltips\":{\n",
       "\"lines\":[\"@..dy..\"]\n",
       "},\n",
       "\"labels\":{\n",
       "\"lines\":[\"@..label..\"],\n",
       "\"use_layer_color\":false\n",
       "}\n",
       "},{\n",
       "\"geom\":\"crossbar\",\n",
       "\"data\":{\n",
       "\"..value..\":[200.0,400.0,250.0,500.0,330.0,480.0,430.0,710.0,685.0,685.0],\n",
       "\"..flow_type..\":[\"Absolute\",\"Increase\",\"Decrease\",\"Increase\",\"Decrease\",\"Increase\",\"Decrease\",\"Increase\",\"Decrease\",\"Total\"],\n",
       "\"..x..\":[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0],\n",
       "\"..ymax..\":[200.0,null,null,null,null,null,null,null,null,685.0],\n",
       "\"..ymin..\":[0.0,null,null,null,null,null,null,null,null,0.0],\n",
       "\"..label..\":[200.0,200.0,-150.0,250.0,-170.0,150.0,-50.0,280.0,-25.0,685.0]\n",
       "},\n",
       "\"mapping\":{\n",
       "\"x\":\"..x..\",\n",
       "\"ymin\":\"..ymin..\",\n",
       "\"ymax\":\"..ymax..\",\n",
       "\"fill\":\"..flow_type..\"\n",
       "},\n",
       "\"color\":\"black\",\n",
       "\"size\":0.0,\n",
       "\"linetype\":1,\n",
       "\"width\":0.9,\n",
       "\"show_legend\":false,\n",
       "\"tooltips\":{\n",
       "\"disable_splitting\":true,\n",
       "\"lines\":[\"@..value..\"]\n",
       "},\n",
       "\"labels\":{\n",
       "\"lines\":[\"@..label..\"],\n",
       "\"use_layer_color\":false\n",
       "}\n",
       "},{\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\",\n",
       "\"label\":\"name\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"data\":{\n",
       "\"x\":[1.5,3.5,5.5,7.5],\n",
       "\"name\":[\"Q1\",\"Q2\",\"Q3\",\"Q4\"],\n",
       "\"y\":[750.0,750.0,750.0,750.0]\n",
       "},\n",
       "\"size\":8.0,\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"text\",\n",
       "\"data_meta\":{\n",
       "\"series_annotations\":[{\n",
       "\"type\":\"str\",\n",
       "\"column\":\"name\"\n",
       "},{\n",
       "\"type\":\"float\",\n",
       "\"column\":\"x\"\n",
       "},{\n",
       "\"type\":\"int\",\n",
       "\"column\":\"y\"\n",
       "}]\n",
       "}\n",
       "},{\n",
       "\"mapping\":{\n",
       "\"x\":\"x\",\n",
       "\"y\":\"y\",\n",
       "\"label\":\"text\"\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"data\":{\n",
       "\"x\":[2.5,6.5],\n",
       "\"y\":[100.0,100.0],\n",
       "\"text\":[\"Before AI\\nintroduction\",\"After AI\\nintroduction\"]\n",
       "},\n",
       "\"size\":12.0,\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"text\",\n",
       "\"data_meta\":{\n",
       "\"series_annotations\":[{\n",
       "\"type\":\"str\",\n",
       "\"column\":\"text\"\n",
       "},{\n",
       "\"type\":\"float\",\n",
       "\"column\":\"x\"\n",
       "},{\n",
       "\"type\":\"int\",\n",
       "\"column\":\"y\"\n",
       "}]\n",
       "}\n",
       "}],\n",
       "\"data_meta\":{\n",
       "\"series_annotations\":[{\n",
       "\"type\":\"int\",\n",
       "\"column\":\"..ymin..\"\n",
       "},{\n",
       "\"type\":\"int\",\n",
       "\"column\":\"..ymiddle..\"\n",
       "},{\n",
       "\"type\":\"int\",\n",
       "\"column\":\"..ymax..\"\n",
       "},{\n",
       "\"type\":\"int\",\n",
       "\"column\":\"..initial..\"\n",
       "},{\n",
       "\"type\":\"int\",\n",
       "\"column\":\"..value..\"\n",
       "},{\n",
       "\"type\":\"int\",\n",
       "\"column\":\"..dy..\"\n",
       "},{\n",
       "\"type\":\"int\",\n",
       "\"column\":\"..label..\"\n",
       "},{\n",
       "\"type\":\"str\",\n",
       "\"column\":\"Accounts\"\n",
       "},{\n",
       "\"type\":\"int\",\n",
       "\"column\":\"Values\"\n",
       "},{\n",
       "\"type\":\"str\",\n",
       "\"column\":\"Measure\"\n",
       "}]\n",
       "},\n",
       "\"theme\":{\n",
       "\"axis_tooltip\":{\n",
       "\"blank\":true\n",
       "},\n",
       "\"label_text\":{\n",
       "\"blank\":false\n",
       "}\n",
       "},\n",
       "\"spec_id\":\"1\"\n",
       "};\n",
       "           window.letsPlotCall(function() { fig = LetsPlot.buildPlotFromProcessedSpecs(plotSpec, containerDiv, sizing); });\n",
       "       } else {\n",
       "           fig.updateView({});\n",
       "       }\n",
       "   }\n",
       "   \n",
       "   const renderImmediately = \n",
       "       forceImmediateRender || (\n",
       "           sizing.width_mode === 'FIXED' && \n",
       "           (sizing.height_mode === 'FIXED' || sizing.height_mode === 'SCALED')\n",
       "       );\n",
       "   \n",
       "   if (renderImmediately) {\n",
       "       renderPlot();\n",
       "   }\n",
       "   \n",
       "   if (!renderImmediately || responsive) {\n",
       "       // Set up observer for initial sizing or continuous monitoring\n",
       "       var observer = new ResizeObserver(function(entries) {\n",
       "           for (let entry of entries) {\n",
       "               if (entry.contentBoxSize && \n",
       "                   entry.contentBoxSize[0].inlineSize > 0) {\n",
       "                   if (!responsive && observer) {\n",
       "                       observer.disconnect();\n",
       "                       observer = null;\n",
       "                   }\n",
       "                   renderPlot();\n",
       "                   if (!responsive) {\n",
       "                       break;\n",
       "                   }\n",
       "               }\n",
       "           }\n",
       "       });\n",
       "       \n",
       "       observer.observe(containerDiv);\n",
       "   }\n",
       "   \n",
       "   // ----------\n",
       "   })();\n",
       "   \n",
       "   </script>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "// Waterfall data\n",
    "val df = mapOf(\n",
    "    \"Accounts\" to listOf(\"initial\", \"revenue\", \"costs\", \"revenue\", \"costs\", \"revenue\", \"costs\", \"revenue\", \"costs\", \"total\"),\n",
    "    \"Values\" to listOf(200, 200, -150, 250, -170, 150, -50, 280, -25, null),\n",
    "    \"Measure\" to listOf(\n",
    "        \"absolute\", \"relative\", \"relative\", \"relative\", \"relative\",\n",
    "        \"relative\", \"relative\", \"relative\", \"relative\", \"total\"\n",
    "    )\n",
    ")\n",
    "\n",
    "// Background band layer and its data\n",
    "val quarterData = mapOf(\n",
    "    \"period_start\" to listOf(0.5, 4.5),\n",
    "    \"period_end\" to listOf(4.5, 8.5),\n",
    "    \"ai_introduced\" to listOf(false, true)\n",
    ")\n",
    "\n",
    "val quarterLayer = geomBand(\n",
    "    data = quarterData,\n",
    "    alpha = 0.2,\n",
    "    // We use \"paint_a\" to color the bands based on a separate category (e.g., quarters),\n",
    "    // so they have their own color palette independent from the waterfalls\n",
    "    fillBy = \"paint_a\",\n",
    "    colorBy = \"paint_a\"\n",
    ") {\n",
    "    xmin = \"period_start\"\n",
    "    xmax = \"period_end\"\n",
    "    paint_a = \"ai_introduced\"\n",
    "}\n",
    "\n",
    "// Foreground layers and their data\n",
    "val quarterLabelData = mapOf(\n",
    "    \"name\" to listOf(\"Q1\", \"Q2\", \"Q3\", \"Q4\"),\n",
    "    \"x\" to listOf(1.5, 3.5, 5.5, 7.5),\n",
    "    \"y\" to List(4) { 750 }\n",
    ")\n",
    "\n",
    "val quarterAiStatusData = mapOf(\n",
    "    \"text\" to listOf(\"Before AI\\nintroduction\", \"After AI\\nintroduction\"),\n",
    "    \"x\" to listOf(2.5, 6.5),\n",
    "    \"y\" to listOf(100, 100)\n",
    ")\n",
    "\n",
    "val textLayers = geomText(data = quarterLabelData, size = 8.0) {\n",
    "    x = \"x\"\n",
    "    y = \"y\"\n",
    "    label = \"name\"\n",
    "} + geomText(data = quarterAiStatusData, size = 12.0) {\n",
    "    x = \"x\"\n",
    "    y = \"y\"\n",
    "    label = \"text\"\n",
    "}\n",
    "\n",
    "// Final plot\n",
    "val p = waterfallPlot(\n",
    "    data = df,\n",
    "    x = \"Accounts\",\n",
    "    y = \"Values\",\n",
    "    measure = \"Measure\",\n",
    "    backgroundLayers = quarterLayer\n",
    ") + \n",
    "    textLayers + \n",
    "    scaleHue(\"paint_a\", guide = \"none\") + \n",
    "    ggsize(750, 450) + \n",
    "    ggtitle(\"Waterfall with additional layers\")\n",
    "\n",
    "p.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Kotlin",
   "language": "kotlin",
   "name": "kotlin"
  },
  "language_info": {
   "codemirror_mode": "text/x-kotlin",
   "file_extension": ".kt",
   "mimetype": "text/x-kotlin",
   "name": "kotlin",
   "nbconvert_exporter": "",
   "pygments_lexer": "kotlin",
   "version": "1.9.23"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
